// The main command parsing module

// import modules
import Stream = require("./ParserStreams");
import Tok = require("./Tokenizer");
import Lex = require("./LexicalParser");
import Syn = require("./SyntaxParser");
import Cmd = require("../Execution/Commands");


// the command parser class itself
export class CommandParser {

    // input source code
    private mSourceCode: string;

    // output command
    private mFinalCommand: Cmd.Command;

    // error message
    private mErrorMessage: string;

    // constructor
    public constructor(sourceCode: string) {
        this.mSourceCode = sourceCode;
        this.mFinalCommand = null;
        this.mFinalCommand = null;
    }

    // property getter for error message
    public get ErrorMessage() {
        return this.mErrorMessage;
    }

    // property getter for final command
    public get FinalCommand() {
        return this.mFinalCommand;
    }

    // the main parsing method
    public Parse(): boolean {
        try {
            // divide source code of the command to tokens
            var tokenizer = new Tok.Tokenizer();
            tokenizer.Parse(this.mSourceCode);
            var tokenStream = new Stream.TokenStream(tokenizer.Tokens);

            // do lexical analysis
            var lexer = new Lex.LexicalParser(tokenStream);
            lexer.Parse();
            var lexStream = new Lex.LexicalStream(lexer.Symbols);

            // finally do syntactical analysis
            var syntax = new Syn.SyntaxParser(lexStream);
            syntax.Parse();

            // save the final command
            this.mFinalCommand = syntax.FinalCommand;
        }
        catch (e) {
            if (e instanceof Syn.SyntaxErrorException) {
                this.mErrorMessage = (<Syn.SyntaxErrorException>e).GetErrorMessage();
            }
            else {
                this.mErrorMessage = e;
            }

            return false;
        }


        // format the source code of the command
        if (this.mFinalCommand != null) {
            var userCommand = <Cmd.UserCommand>this.mFinalCommand;
            userCommand.SetSourceCode(userCommand.FormatSourceCode());
        }

        return true;
    }
}
